#include "wifi_board.h"
#include "audio_codecs/es8311_audio_codec.h"
#include "audio_codecs/no_audio_codec.h"
#include "display/lcd_display.h"
#include "system_reset.h"
#include "font_awesome_symbols.h"
#include "application.h"
#include "button.h"
#include "config.h"
#include "iot/thing_manager.h"
#include "assets/lang_config.h"
#include "led/single_led.h"
#include "mcp_server.h"

#include <wifi_station.h>
#include <esp_log.h>
#include <esp_lcd_panel_vendor.h>
#include <driver/i2c_master.h>
#include <driver/spi_common.h>

#include "wexcube_sdk_server/wexcube_config.h"
#include "wexcube_sdk_server/wexcube_port.h"
#include "wexcube_sdk_server/wexcube.h"

#define TAG "linkdog-wifi"

LV_FONT_DECLARE(font_puhui_20_4);
LV_FONT_DECLARE(font_awesome_20_4);

class linkdog_wifi : public WifiBoard
{
private:
    i2c_master_bus_handle_t i2c_bus_;
    Button volume_up_button_;
    Button volume_down_button_;
    Button boot_button_;
    Display *display_;

    // i2c初始化，音频ES8311
    void InitializeI2c()
    {
        // Initialize I2C peripheral
        i2c_master_bus_config_t i2c_bus_cfg = {
            .i2c_port = I2C_NUM_0,
            .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
            .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
            .clk_source = I2C_CLK_SRC_DEFAULT,
            .glitch_ignore_cnt = 7,
            .intr_priority = 0,
            .trans_queue_depth = 0,
            .flags = {
                .enable_internal_pullup = 1,
            },
        };
        ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
    }

    // SPI初始化，显示屏
    void InitializeSpi()
    {
        spi_bus_config_t buscfg = {};
        buscfg.mosi_io_num = DISPLAY_MOSI_GPIO;
        buscfg.miso_io_num = GPIO_NUM_NC;
        buscfg.sclk_io_num = DISPLAY_CLK_GPIO;
        buscfg.quadwp_io_num = GPIO_NUM_NC;
        buscfg.quadhd_io_num = GPIO_NUM_NC;
        buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
        ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
    }

    // 按钮初始化
    void InitializeButtons()
    {
        boot_button_.OnClick([this]()
                             {
            auto& app = Application::GetInstance();
            if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
                ResetWifiConfiguration();
            }
            app.ToggleChatState(); });
        volume_up_button_.OnClick([this]()
                                  {
            auto codec = GetAudioCodec();
            auto volume = codec->output_volume() + 10;
            if (volume > 100) {
                volume = 100;
            }
            codec->SetOutputVolume(volume);
            GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume)); });

        volume_up_button_.OnLongPress([this]()
                                      {
            GetAudioCodec()->SetOutputVolume(100);
            GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME); });

        volume_down_button_.OnClick([this]()
                                    {
            auto codec = GetAudioCodec();
            auto volume = codec->output_volume() - 10;
            if (volume < 0) {
                volume = 0;
            }
            codec->SetOutputVolume(volume);
            GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume)); });

        volume_down_button_.OnLongPress([this]()
                                        {
            GetAudioCodec()->SetOutputVolume(0);
            GetDisplay()->ShowNotification(Lang::Strings::MUTED); });
    }

    // 显示屏初始化
    void InitializeDisplay()
    {
        esp_lcd_panel_io_handle_t panel_io = nullptr;
        esp_lcd_panel_handle_t panel = nullptr;

        // 液晶屏控制IO初始化
        ESP_LOGD(TAG, "Install panel IO");
        esp_lcd_panel_io_spi_config_t io_config = {};
        io_config.cs_gpio_num = DISPLAY_CS_GPIO;
        io_config.dc_gpio_num = DISPLAY_DC_GPIO;
        io_config.spi_mode = 0;
        io_config.pclk_hz = 40 * 1000 * 1000;
        io_config.trans_queue_depth = 10;
        io_config.lcd_cmd_bits = 8;
        io_config.lcd_param_bits = 8;
        ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));

        // 初始化液晶屏驱动芯片
        ESP_LOGD(TAG, "Install LCD driver");

        esp_lcd_panel_dev_config_t panel_config = {};
        panel_config.reset_gpio_num = DISPLAY_RST_GPIO;
        panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
        panel_config.bits_per_pixel = 16;
        ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));

        esp_lcd_panel_reset(panel);
        esp_lcd_panel_init(panel);
        esp_lcd_panel_invert_color(panel, true);
        esp_lcd_panel_disp_on_off(panel, true);
        display_ = new SpiLcdDisplay(panel_io, panel,
                                     DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
                                     {
                                         .text_font = &font_puhui_20_4,
                                         .icon_font = &font_awesome_20_4,
                                         .emoji_font = font_emoji_64_init(),
                                     });
    }

    // 物联网初始化，添加对 AI 可见设备
    void InitializeIot()
    {
        auto &thing_manager = iot::ThingManager::GetInstance();
        thing_manager.AddThing(iot::CreateThing("Speaker"));
        // 在此扩展IOT设备
    }

    // MCP服务器初始化
    void InitializeMcpServer()
    {
        auto &mcp_server = McpServer::GetInstance();

        // 设置眼睛/灯亮度
        mcp_server.AddTool("self.eyes.set_level", "设置眼睛/灯亮度: 范围0-100\n0为最暗\n100为最亮", PropertyList({Property("level", kPropertyTypeInteger, 0, 100)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int eyesLevel = properties["level"].value<int>();
            ESP_LOGI(TAG, "LinkDog eyes level set to: %d", eyesLevel);
            wex_sendEvent(SLIDER_EYES_LEVEL_ID, eyesLevel);
            return true; });

        // 设置眼睛/灯颜色
        mcp_server.AddTool("self.eyes.set_color", "设置眼睛/灯RBG颜色", PropertyList({Property("r", kPropertyTypeInteger, 0, 255), Property("g", kPropertyTypeInteger, 0, 255), Property("b", kPropertyTypeInteger, 0, 255)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int r = properties["r"].value<int>();
            int g = properties["g"].value<int>();
            int b = properties["b"].value<int>();
            ESP_LOGI(TAG, "LinkDog eyes color set to: r = %d, g = %d, b = %d", r, g, b);
            wex_sendBackColor(BUTTON_EYES_COLOR1_ID, r, g, b);
            return true; });

        // 设置左手角度
        mcp_server.AddTool("self.hand.set_left_hand_angle", "设置左手或左前脚的角度: 范围0-180\n0为最前\n180为最后", PropertyList({Property("angle", kPropertyTypeInteger, 0, 180)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int leftHandAngle = properties["angle"].value<int>();
            ESP_LOGI(TAG, "LinkDog left hand angle set to: %d", leftHandAngle);
            wex_sendEvent(SLIDER_LEFTHAND_ID, leftHandAngle);
            return true; });

        // 设置右手角度
        mcp_server.AddTool("self.hand.set_right_hand_angle", "设置右手或右前脚的角度: 范围0-180\n0为最前\n180为最后", PropertyList({Property("angle", kPropertyTypeInteger, 0, 180)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int rightHandAngle = properties["angle"].value<int>();
            ESP_LOGI(TAG, "LinkDog right hand angle set to: %d", rightHandAngle);
            wex_sendEvent(SLIDER_RIGHTHAND_ID, rightHandAngle);
            return true; });

        // 设置左脚角度
        mcp_server.AddTool("self.leg.set_left_leg_angle", "设置左脚或左后脚的角度: 范围0-180\n0为最前\n180为最后", PropertyList({Property("angle", kPropertyTypeInteger, 0, 180)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int leftLegAngle = properties["angle"].value<int>();
            ESP_LOGI(TAG, "LinkDog left leg angle set to: %d", leftLegAngle);
            wex_sendEvent(SLIDER_LEFTLEG_ID, leftLegAngle);
            return true; });

        // 设置右脚角度
        mcp_server.AddTool("self.leg.set_right_leg_angle", "设置右脚或右后脚的角度: 范围0-180\n0为最前\n180为最后", PropertyList({Property("angle", kPropertyTypeInteger, 0, 180)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int rightLegAngle = properties["angle"].value<int>();
            ESP_LOGI(TAG, "LinkDog right leg angle set to: %d", rightLegAngle);
            wex_sendEvent(SLIDER_RIGHTLEG_ID, rightLegAngle);
            return true; });

        // 运动动作集合1
        mcp_server.AddTool("self.action.group1", "运动动作集合1: {\nleft_right: 左右摇晃\nfront_back: 前后摇晃\n"
                                                 "forward: 前进\nleft: 向左\nright: 向右\nbackward: 后退\nshake_hands: 握手\ncrawl: 匍匐前进或爬行\n}\n"
                                                 "动作持续时间: 范围1-5秒默认2秒",
                           PropertyList({Property("action", kPropertyTypeString),
                                         Property("duration", kPropertyTypeInteger, 1, 5)}),
                           [this](const PropertyList &properties) -> ReturnValue
                           {
                               const std::string &action = properties["action"].value<std::string>();
                               int duration = properties["duration"].value<int>();
                               ESP_LOGI(TAG, "LinkDog action: %s, duration: %d", action.c_str(), duration);
                               if (action == "forward")
                               {
                                   wex_sendEvent(BUTTON_FORWARD_ID, 1);
                               }
                               else if (action == "left")
                               {
                                   wex_sendEvent(BUTTON_LEFT_ID, 1);
                               }
                               else if (action == "right")
                               {
                                   wex_sendEvent(BUTTON_RIGHT_ID, 1);
                               }
                               else if (action == "backward")
                               {
                                   wex_sendEvent(BUTTON_BACKWARD_ID, 1);
                               }
                               else if (action == "left_right")
                               {
                                   wex_sendEvent(BUTTON_LEFTRIGHT_ID, 1);
                               }
                               else if (action == "front_back")
                               {
                                   wex_sendEvent(BUTTON_FRONTBACK_ID, 1);
                               }
                               else if (action == "shake_hands")
                               {
                                   wex_sendEvent(BUTTON_HANDSHAKE_ID, 1);
                               }
                               else if (action == "crawl")
                               {
                                   wex_sendEvent(BUTTON_CRAWL_ID, 1);
                               }
                               else
                               {
                                   return false;
                               }

                               vTaskDelay(pdMS_TO_TICKS(1000 * duration));

                               // 停止动作
                               wex_sendEvent(BUTTON_FORWARD_ID, 0);
                               wex_sendEvent(BUTTON_BACKWARD_ID, 0);

                               return true;
                           });

        // 运动动作集合2
        mcp_server.AddTool("self.action.group2", "运动动作集合2: {\nstand_up: 站立\nget_down: 趴下\nsit_down: 坐下\nstretch: 伸懒腰\nhead_forward: 前顶\nhead_back: 后顶\n}",
                           PropertyList({
                               Property("action", kPropertyTypeString),
                           }),
                           [this](const PropertyList &properties) -> ReturnValue
                           {
                               const std::string &action = properties["action"].value<std::string>();
                               ESP_LOGI(TAG, "LinkDog action: %s", action.c_str());
                               if (action == "stand_up")
                               {
                                   wex_sendEvent(BUTTON_STANDUP_ID, 1);
                               }
                               else if (action == "get_down")
                               {
                                   wex_sendEvent(BUTTON_GETDOWN_ID, 1);
                               }
                               else if (action == "sit_down")
                               {
                                   wex_sendEvent(BUTTON_SITDOWN_ID, 1);
                               }
                               else if (action == "stretch")
                               {
                                   wex_sendEvent(BUTTON_STRETCH_ID, 1);
                               }
                               else if (action == "head_forward")
                               {
                                   wex_sendEvent(BUTTON_HEADFWD_ID, 1);
                               }
                               else if (action == "head_back")
                               {
                                   wex_sendEvent(BUTTON_HEADBACK_ID, 1);
                               }
                               else
                               {
                                   return false;
                               }
                               return true;
                           });

        // 运动速度控制
        mcp_server.AddTool("self.action.set_speed", "运动速度控制: \n范围1-5\n1为最慢\n5为最快", PropertyList({Property("speed", kPropertyTypeInteger, 1, 5)}), [this](const PropertyList &properties) -> ReturnValue
                           {
            int speedLevel = properties["speed"].value<int>();
            ESP_LOGI(TAG, "LinkDog speed level set to: %d", speedLevel);
            wex_sendEvent(SLIDER_MOVE_SPEED_ID, speedLevel);
            return true; });

        // 自定义指令1: 上才艺
        mcp_server.AddTool("self.action.perform_talent", "上才艺", PropertyList(), [this](const PropertyList &properties) -> ReturnValue
                           {
            ESP_LOGI(TAG, "LinkDog perform talent");

            wex_sendEvent(BUTTON_FORWARD_ID, 1);
            vTaskDelay(pdMS_TO_TICKS(1000));
            wex_sendEvent(BUTTON_FORWARD_ID, 0);
            wex_sendEvent(BUTTON_BACKWARD_ID, 1);
            vTaskDelay(pdMS_TO_TICKS(1000));
            wex_sendEvent(BUTTON_BACKWARD_ID, 0);
            wex_sendEvent(SLIDER_LEFTLEG_ID, 75);
            wex_sendEvent(SLIDER_RIGHTLEG_ID, 75);
            vTaskDelay(pdMS_TO_TICKS(200));

            wex_u8_t angle = 150;
            for (int i= 0; i < 8; i++)
            {
                wex_sendEvent(SLIDER_LEFTHAND_ID, angle);
                wex_sendEvent(SLIDER_RIGHTHAND_ID, angle);
                angle -= 5;
                vTaskDelay(pdMS_TO_TICKS(200));
            }
            wex_sendEvent(SLIDER_LEFTLEG_ID, 180);
            wex_sendEvent(SLIDER_RIGHTLEG_ID, 180);

            for (int j = 0; j < 3; j++)
            {
                for (int i= 0; i < 3; i++)
                {
                    angle += 5;
                    wex_sendEvent(SLIDER_LEFTHAND_ID, angle);
                    wex_sendEvent(SLIDER_RIGHTHAND_ID, angle);
                    vTaskDelay(pdMS_TO_TICKS(200));
                }
                for (int i= 0; i < 3; i++)
                {
                    angle -= 5;
                    wex_sendEvent(SLIDER_LEFTHAND_ID, angle);
                    wex_sendEvent(SLIDER_RIGHTHAND_ID, angle);
                    vTaskDelay(pdMS_TO_TICKS(200));
                }
            }

            wex_sendEvent(SLIDER_LEFTLEG_ID, 0);
            wex_sendEvent(SLIDER_RIGHTLEG_ID, 0);
            for (int i= 0; i < 6; i++)
            {
                angle += 10;
                wex_sendEvent(SLIDER_LEFTHAND_ID, angle);
                wex_sendEvent(SLIDER_RIGHTHAND_ID, angle);
                vTaskDelay(pdMS_TO_TICKS(200));
            }
            wex_sendEvent(SLIDER_RIGHTHAND_ID, 90);
            vTaskDelay(pdMS_TO_TICKS(200));
            wex_sendEvent(SLIDER_LEFTHAND_ID, 90);

            wex_sendEvent(BUTTON_STANDUP_ID, 1);

            return true; });
    }

public:
    // 构造函数
    linkdog_wifi() : volume_up_button_(VOLUME_UP_BUTTON_GPIO),
                     volume_down_button_(VOLUME_DOWN_BUTTON_GPIO),
                     boot_button_(BOOT_BUTTON_GPIO)
    {
        InitializeI2c();
        InitializeSpi();
        InitializeDisplay();
        InitializeButtons();
        InitializeIot();
        InitializeMcpServer();

        wex_init();
    }

    // 获取音频编码器
    virtual AudioCodec *GetAudioCodec() override
    {
        static Es8311AudioCodec audio_codec(
            i2c_bus_,
            I2C_NUM_0,
            AUDIO_INPUT_SAMPLE_RATE,
            AUDIO_OUTPUT_SAMPLE_RATE,
            AUDIO_I2S_GPIO_MCLK,
            AUDIO_I2S_GPIO_BCLK,
            AUDIO_I2S_GPIO_WS,
            AUDIO_I2S_GPIO_DOUT,
            AUDIO_I2S_GPIO_DIN,
            AUDIO_CODEC_PA_PIN,
            AUDIO_CODEC_ES8311_ADDR);
        return &audio_codec;
    }

    virtual Display *GetDisplay() override
    {
        return display_;
    }

    virtual Backlight *GetBacklight() override
    {
        static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
        return &backlight;
    }

    virtual Led *GetLed() override
    {
        static SingleLed led(BUILTIN_LED_GPIO);
        return &led;
    }
};

DECLARE_BOARD(linkdog_wifi);
